//
// Created by Administrator on 2021/10/26.
//

#include "Model.h"

//obj文件解析
const static String SKIP = "#";
const static String MTLLIB = "mtllib";
const static String NAME = "o";
const static String VERTEX = "v";
const static String UV = "vt";
const static String NORMAL = "vn";
const static String USEMTL = "usemtl";
const static String S = "s";//todo what is this?
const static String INDEX = "f";

//上次的时间
static float lastTime = 0.0f;
static float angleStep = 30.0f;

Model::Model(String objFilePath) {
    type = GET_CLASS(__FILE__);
    name = type + "_" + id;

    this->objFilePath = objFilePath;
}

void Model::onInit() {
    MAssert::check(!objFilePath.empty());

    BufferGeometry *bufferGeometry = new BufferGeometry(); // object3d 统一回收

//    useArray(bufferGeometry);
    String objContent = FileUtil::readStrFromFile(objFilePath);
    MAssert::check(!objContent.empty());

    std::vector<Vector3> v_array = regexVector3Array(objContent, R"(v{1}[\s]+.*)");
    std::vector<Vector3> vt_array = regexVector3Array(objContent, R"(vt{1}[\s]+.*)");
    std::vector<Vector3> vn_array = regexVector3Array(objContent, R"(vn{1}[\s]+.*)");
    parseIndices(objContent,   v_array, vt_array, vn_array, bufferGeometry);

    // 释放
    std::vector<Vector3>().swap(v_array);
    std::vector<Vector3>().swap(vt_array);
    std::vector<Vector3>().swap(vn_array);
    geometries.push_back(bufferGeometry);

    location.z = -2.0f;
    Object3D::onInit();
}


std::vector<Vector3> Model::regexVector3Array(const String &objContent, const String &regex) const {
    std::regex ex(regex.c_str());

    std::vector<Vector3> array;
    std::vector<String> eachArray;
    for (std::sregex_iterator it(objContent.getSelf().begin(), objContent.getSelf().end(), ex), end;
         it != end;
         ++it)
    {
        eachArray.clear();
        String c = it->str();
        c.splitWithRegex("[\\s]+", eachArray);

        Vector3 v(0.0f, 0.0f, 0.0f);
        if(eachArray.size() > 1){
            v.x = atof(eachArray[1].c_str());
        };
        if(eachArray.size() > 2){
            v.y = atof(eachArray[2].c_str());
        };
        if(eachArray.size() > 3){
            v.z = atof(eachArray[3].c_str());
        };
        array.push_back(v);
    }

    return array;
}

void Model::parseIndices(String objContent, std::vector<Vector3> v_array, std::vector<Vector3> vt_array, std::vector<Vector3> vn_array, BufferGeometry *bufferGeometry) {

    String regex = R"(f{1}\s+\d.*)";
    std::regex ex(regex.c_str());

    // 是否需要进行三角面转换
    bool convertTriangle = false;

    std::vector<String> eachArray;
    std::vector<String> vertexArray;
//    std::vector<int> v_index_array;
//    std::vector<int> vt_index_array;
//    std::vector<int> vn_index_array;

    long ct = 0;

    for (std::sregex_iterator it(objContent.getSelf().begin(), objContent.getSelf().end(), ex), end;
         it != end;
         ++it)
    {
        eachArray.clear();
        String c = it->str();
        c.splitWithRegex("\\s+", eachArray);

        if(eachArray.size() - 1 != 3){
            convertTriangle = true;
        }

        for(int i = 1; i < eachArray.size(); i++){
            vertexArray.clear();
            String a = eachArray[i];
            a.splitWithRegex("/", vertexArray);

            // v
            if(vertexArray.size() > 0){
                int index = atoi(vertexArray[0].c_str()) - 1;
//                auto existIndex = std::find(v_index_array.begin(), v_index_array.end(), index);
//                if(existIndex == v_index_array.end()) {
                    bufferGeometry->vertices.push_back(v_array[index].x);
                    bufferGeometry->vertices.push_back(v_array[index].y);
                    bufferGeometry->vertices.push_back(v_array[index].z);

//                    v_index_array.push_back(index);
//                }
            }

            //vt
            if(vertexArray.size() > 1){
                int vt_index = atoi(vertexArray[1].c_str()) - 1;
//                auto existIndex = std::find(vt_index_array.begin(), vt_index_array.end(), vt_index);
//                if(existIndex == vt_index_array.end()) {
                    bufferGeometry->uvs.push_back(vt_array[vt_index].x);
                    bufferGeometry->uvs.push_back(vt_array[vt_index].y);

//                    v_index_array.push_back(vt_index);
//                }
            }

            //vn
            if(vertexArray.size() > 2){
                int vn_index = atoi(vertexArray[2].c_str()) - 1;
//                auto existIndex = std::find(vn_index_array.begin(), vn_index_array.end(), vn_index);
//                if(existIndex == vn_index_array.end()) {
                    bufferGeometry->normals.push_back(vn_array[vn_index].x);
                    bufferGeometry->normals.push_back(vn_array[vn_index].y);
                    bufferGeometry->normals.push_back(vn_array[vn_index].z);

//                    vn_index_array.push_back(vn_index);
//                }
            }

            ct ++;
        }
    }

    for(int i = 1; i <= ct; i++){
            // 转换三角面
            if(convertTriangle) {
                if (i % 4 == 0) {
                    bufferGeometry->indices.push_back(i - 4);//0 4 8
                    bufferGeometry->indices.push_back(i - 3);//1 5 9
                    bufferGeometry->indices.push_back(i - 2);//2 6 10
                    bufferGeometry->indices.push_back(i - 4);//0 4 8
                    bufferGeometry->indices.push_back(i - 2);//2 6 10
                    bufferGeometry->indices.push_back(i - 1);//3 7 11
                }
            }else {
                bufferGeometry->indices.push_back(i - 1);
            }
    }
    log_info("模式是否是三角面：%s,索引总数：%d", convertTriangle ? "否" : "是", bufferGeometry->indices.size());

    // 释放
    std::vector<String>().swap(eachArray);
    std::vector<String>().swap(vertexArray);
//    std::vector<int>().swap(v_index_array);
//    std::vector<int>().swap(vt_index_array);
//    std::vector<int>().swap(vn_index_array);
}

/**
 * 使用数组方式存储解析 TODO 等待优化
 * @param bufferGeometry
 */
void Model::useArray(BufferGeometry *bufferGeometry) {
    std::vector<String> objContent = FileUtil::readLineStrFromFile(objFilePath);
    std::vector<String> lineArray;

    for (auto iterator = objContent.begin(); iterator != objContent.end(); ++iterator) {
        String line = *iterator;
        if(line.empty()) continue;

        lineArray.clear();

        // 空格分隔
        line.splitWithRegex("[\\s]+", lineArray);
        if(lineArray.empty()) continue;

        String first = lineArray[0];
        if(first == SKIP) continue;

        // parset start
        if(MTLLIB == first){
            //log_info("%s", line.c_str());
        }
        else if(NAME == first) {
            //log_info("%s", line.c_str());
        }
        else if(VERTEX == first) {
            parseVertex(lineArray, bufferGeometry);
        }
        else if(UV == first) {
            parseUV(lineArray, bufferGeometry);
        }
        else if(NORMAL == first) {
            parseNormal(lineArray, bufferGeometry);
        }
        else if(USEMTL == first) {
            //log_info("%s", line.c_str());
        }
        else if(S == first) {
            //log_info("%s", line.c_str());
        }
        else if(INDEX == first) {
            parseIndex(lineArray, bufferGeometry);
        }
    }
}

/**
* 解析顶点数据
* @param lineArray 文本
*/
void Model::parseVertex(std::vector<String> lineArray, BufferGeometry *bufferGeometry) {
    MAssert::check(bufferGeometry);

    int size = lineArray.size();
    //二维以下不处理
    MAssert::check(size > 3);

    Vector3 v(0.0f, 0.0f, 0.0f);
    if(size >= 3) {
        v.x = atof(lineArray[1].c_str());
        v.y = atof(lineArray[2].c_str());
    }
    if(size >= 4) {
        v.z = atof(lineArray[3].c_str());
    }

    bufferGeometry->vertices.push_back(v.x);
    bufferGeometry->vertices.push_back(v.y);
    bufferGeometry->vertices.push_back(v.z);
}

/**
 * 解析UV数据
 * @param lineArray 文本
 */
void Model::parseUV(std::vector<String> lineArray, BufferGeometry *bufferGeometry) {
    MAssert::check(bufferGeometry);
    int size = lineArray.size();
    MAssert::check(size > 2);

    Vector3 v(0.0f, 0.0f, 0.0f);
    v.x = atof(lineArray[1].c_str());
    v.y = atof(lineArray[2].c_str());

    bufferGeometry->uvs.push_back(v.x);
    bufferGeometry->uvs.push_back(v.y);
    //bufferGeometry->uvs.push_back(v.z); uv 只有 xy，但我又不想弄个 vector2
}

/**
 * 解析法线数据
 * @param lineArray 文本
 */
void Model::parseNormal(std::vector<String> lineArray, BufferGeometry *bufferGeometry) {
    MAssert::check(bufferGeometry);

    int size = lineArray.size();
    //二维以下不处理
    MAssert::check(size > 3);

    Vector3 v(0.0f, 0.0f, 0.0f);
    if(size >= 3) {
        v.x = atof(lineArray[1].c_str());
        v.y = atof(lineArray[2].c_str());
    }
    if(size >= 4) {
        v.z = atof(lineArray[3].c_str());
    }

    bufferGeometry->normals.push_back(v.x);
    bufferGeometry->normals.push_back(v.y);
    bufferGeometry->normals.push_back(v.z);
}

/**
 * 解析索引数据
 * @param lineArray 文本
 */
void Model::parseIndex(std::vector<String> lineArray, BufferGeometry *bufferGeometry) {
    MAssert::check(bufferGeometry);
    int size = lineArray.size();
    MAssert::check(size > 2);//至少有一个顶点索引

    std::vector<String> indexArray;

    bool bTriangle = false;
    if(size == 4){ //1(头) + 3
        //三角面
        bTriangle = true;
    }else if(size == 5){
        //四边形面
        bTriangle = false;
    }else {
        log_warn("未知索引位置个数，当前索引个数为%d", size);
    }

    //每个面的顶点索引缓存
    std::vector<int> eachFaceVertexIndexArray;

    for(int i = 1; i < size; i ++){ // 跳过 first，从1开始
        indexArray.clear();

        lineArray[i].split("/", indexArray);

        if(indexArray.size() > 0) {
            if (bTriangle) {
                // 三角面处理
                bufferGeometry->indices.push_back(atoi(indexArray[0].c_str()) - 1);//索引值从1开始的，-1置为0
            }else{
                // 四角面 --> 三角面
                eachFaceVertexIndexArray.push_back(atoi(indexArray[0].c_str()));

                if (eachFaceVertexIndexArray.size() == 4) {
                    bufferGeometry->indices.push_back(eachFaceVertexIndexArray[0] - 1);//索引值从1开始的，-1置为0
                    bufferGeometry->indices.push_back(eachFaceVertexIndexArray[1] - 1);
                    bufferGeometry->indices.push_back(eachFaceVertexIndexArray[2] - 1);
                    bufferGeometry->indices.push_back(eachFaceVertexIndexArray[0] - 1);
                    bufferGeometry->indices.push_back(eachFaceVertexIndexArray[2] - 1);
                    bufferGeometry->indices.push_back(eachFaceVertexIndexArray[3] - 1);

                    eachFaceVertexIndexArray.clear();
                }
            }
        }
    }

    eachFaceVertexIndexArray.clear();
    indexArray.clear();
}

void Model::onRender(float elapsedTime, Matrix4x4 proj, Matrix4x4 view, Matrix4x4 pworld) {
    float dtime = elapsedTime - lastTime;
    lastTime = elapsedTime;

    rotation.y += dtime * angleStep;
    if(rotation.y > 360.0f || rotation.y < 0.0f){
        angleStep = -angleStep;
    }

    Object3D::onRender(elapsedTime, proj, view, pworld);
}



























